// Copyright (c) 2024 embeddedboys developers

// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdbool.h>

#include "pico/time.h"
#include "pico/stdio.h"
#include "pico/stdlib.h"
#include "pico/platform.h"
#include "pico/stdio_uart.h"

#include "hardware/pll.h"
#include "hardware/vreg.h"
#include "hardware/clocks.h"
#include "hardware/timer.h"

#include "lvgl/lvgl.h"
// #include "lvgl/demos/lv_demos.h"
// #include "lvgl/examples/lv_examples.h"
#include "porting/lv_port_disp_template.h"
#include "porting/lv_port_indev_template.h"

#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"

#include "backlight.h"

#include "debug.h"

#include "ui.h"

extern void update_chart_task(lv_timer_t *timer);
extern objects_t objects;
lv_timer_t *update_timer = NULL;

#include "ads1115.h"

#define I2C_PORT i2c0
#define I2C_FREQ 400000
#define ADS1115_I2C_ADDR 0x48
const uint8_t SDA_PIN = 12;
const uint8_t SCL_PIN = 13;

struct ads1115_adc adc;


// NTC 温度计算
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

typedef struct
{
    double r0;
    double t0_kelvin;
    double b_value;
} NTCThermistor;

NTCThermistor *ntc;

// 构造函数（带错误检查）
NTCThermistor *NTCThermistor_new(double r0, double t0, double b_value)
{
    if (r0 <= 0 || b_value <= 0)
    {
        fprintf(stderr, "Error: R0和B值必须为正值\n");
        return NULL;
    }

    NTCThermistor *ntc = (NTCThermistor *)malloc(sizeof(NTCThermistor));
    if (!ntc)
    {
        perror("Memory allocation failed");
        return NULL;
    }

    ntc->r0 = r0;
    ntc->t0_kelvin = t0 + 273.15;
    ntc->b_value = b_value;
    return ntc;
}

// 温度计算函数（带错误检查）
double resistance_to_temp(NTCThermistor *ntc, double resistance)
{
    if (!ntc)
    {
        fprintf(stderr, "Error: 无效对象指针\n");
        return NAN;
    }

    if (resistance <= 0)
    {
        fprintf(stderr, "Error: 电阻值必须为正值\n");
        return NAN;
    }

    const double ln_r_ratio = log(resistance / ntc->r0);
    const double inv_t = (1.0 / ntc->t0_kelvin) + (ln_r_ratio / ntc->b_value);
    return (1.0 / inv_t) - 273.15;
}

// 释放内存
void NTCThermistor_free(NTCThermistor *ntc)
{
    free(ntc);
}

/* 示例用法：
int main() {
    NTCThermistor* ntc = NTCThermistor_new(100000.0, 25.0, 3950.0);
    if (!ntc) return 1;

    printf("Temperature: %.2f℃\n", resistance_to_temp(ntc, 100000.0));

    NTCThermistor_free(ntc);
    return 0;
}
*/

// 全局变量定义
TaskHandle_t read_adc_value_handler = NULL; // 任务句柄
volatile bool read_adc_value_run_flag = true;
volatile double temp = 24.64;

SemaphoreHandle_t xTempMutex = NULL;
SemaphoreHandle_t xFlagMutex = NULL;

// 回调函数
void update_value_cb(lv_timer_t *timer)
{
    char buf[16];
    // i2c read temp sensor

    if (xSemaphoreTake(xTempMutex, portMAX_DELAY) == pdTRUE)
    {
        snprintf(buf, sizeof(buf), "%.2f", temp);
        lv_label_set_text(objects.value_label, buf);

        if (xSemaphoreTake(xFlagMutex, portMAX_DELAY) == pdTRUE)
        {
            if (read_adc_value_run_flag)
            {
                update_chart_task(timer);
            }
            xSemaphoreGive(xFlagMutex);
        }
        xSemaphoreGive(xTempMutex);
    }
}

void action_trun_on_of_handle(lv_event_t *e)
{
    objects_t *ui = (objects_t *)e->user_data;
    // 修改按钮标签
    const char *current_btn_text = lv_label_get_text(ui->btn_label);
    if (strcmp(current_btn_text, "ON"))
    {
        if (xSemaphoreTake(xFlagMutex, portMAX_DELAY) == pdTRUE)
        {
            read_adc_value_run_flag = true;
            xSemaphoreGive(xFlagMutex);
        }
    }
    else
    {
        if (xSemaphoreTake(xFlagMutex, portMAX_DELAY) == pdTRUE)
        {
            read_adc_value_run_flag = false;
            xSemaphoreGive(xFlagMutex);
        }
    }
    lv_label_set_text(ui->btn_label, strcmp(current_btn_text, "OFF") ? "OFF" : "ON");
}

static portTASK_FUNCTION(read_adc_value, pvParameters)
{

    // Data containers
    float volts;
    uint16_t adc_value;
    bool current_flag;
    for (;;)
    {

        if (xSemaphoreTake(xFlagMutex, portMAX_DELAY) == pdTRUE)
        {
            current_flag = read_adc_value_run_flag;
            xSemaphoreGive(xFlagMutex);
        }
        if (current_flag)
        {
            // Read a value, convert to volts, and print.
            ads1115_read_adc(&adc_value, &adc);
            volts = ads1115_raw_to_volts(adc_value, &adc);
            double r_ntc = volts / ((4.65 - volts) / 305000.0);
            if (xSemaphoreTake(xTempMutex, portMAX_DELAY) == pdTRUE)
            {
                temp = resistance_to_temp(ntc, r_ntc);
                xSemaphoreGive(xTempMutex);
            }
            printf("ADC: %u  Voltage: %f  temp: %f\n", adc_value, volts, temp);
        }

        vTaskDelay(pdMS_TO_TICKS(100));
    }
    vTaskDelete(NULL);
}

QueueHandle_t xToFlushQueue = NULL;

void vApplicationTickHook()
{
    lv_tick_inc(1);
}

const TickType_t xPeriod = pdMS_TO_TICKS(5);
static portTASK_FUNCTION(lv_timer_task_handler, pvParameters)
{
    TickType_t xLastWakeTime;

    xLastWakeTime = xTaskGetTickCount();

    for (;;)
    {
        vTaskDelayUntil(&xLastWakeTime, xPeriod);
        lv_timer_handler();
    }
    vTaskDelete(NULL);
}

extern int factory_test(void);

int main(void)
{
    /* NOTE: DO NOT MODIFY THIS BLOCK */
#define CPU_SPEED_MHZ (DEFAULT_SYS_CLK_KHZ / 1000)
    if (CPU_SPEED_MHZ > 266 && CPU_SPEED_MHZ <= 360)
        vreg_set_voltage(VREG_VOLTAGE_1_20);
    else if (CPU_SPEED_MHZ > 360 && CPU_SPEED_MHZ <= 396)
        vreg_set_voltage(VREG_VOLTAGE_1_25);
    else if (CPU_SPEED_MHZ > 396)
        vreg_set_voltage(VREG_VOLTAGE_MAX);
    else
        vreg_set_voltage(VREG_VOLTAGE_DEFAULT);

    set_sys_clock_khz(CPU_SPEED_MHZ * 1000, true);
    clock_configure(clk_peri,
                    0,
                    CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS,
                    CPU_SPEED_MHZ * MHZ,
                    CPU_SPEED_MHZ * MHZ);
    stdio_uart_init_full(uart0, 115200, 16, 17);

    printf("\n\n\n init i2c0 \n");
    // Initialise I2C
    i2c_init(I2C_PORT, I2C_FREQ);
    gpio_set_function(SDA_PIN, GPIO_FUNC_I2C);
    gpio_set_function(SCL_PIN, GPIO_FUNC_I2C);
    gpio_pull_up(SDA_PIN);
    gpio_pull_up(SCL_PIN);

    // Initialise ADC
    ads1115_init(I2C_PORT, ADS1115_I2C_ADDR, &adc);

    // Modify the default configuration as needed. In this example the
    // signal will be differential, measured between pins A0 and A3,
    // and the full-scale voltage range is set to +/- 4.096 V.
    ads1115_set_input_mux(ADS1115_MUX_SINGLE_0, &adc);
    ads1115_set_pga(ADS1115_PGA_2_048, &adc);
    ads1115_set_data_rate(ADS1115_RATE_128_SPS, &adc);

    // Write the configuration for this to have an effect.
    ads1115_write_config(&adc);

    ntc = NTCThermistor_new(100000.0, 25.0, 3950.0);

    printf("\n\n\nPICO DM QD3503728 LVGL Porting\n");

    xToFlushQueue = xQueueCreate(2, sizeof(struct video_frame));
    // 初始化信号量
    xTempMutex = xSemaphoreCreateMutex();
    xFlagMutex = xSemaphoreCreateMutex();

    lv_init();
    lv_port_disp_init();

#if INDEV_DRV_USED
    lv_port_indev_init();
#endif

    printf("Starting demo\n");

    ui_init();

    update_timer = lv_timer_create(update_value_cb, 100, &objects);

    TaskHandle_t lvgl_task_handle;
    xTaskCreate(lv_timer_task_handler, "lvgl_task", 2048, NULL, (tskIDLE_PRIORITY + 3), &lvgl_task_handle);
    vTaskCoreAffinitySet(lvgl_task_handle, (1 << 0));

    TaskHandle_t video_flush_handler;
    xTaskCreate(video_flush_task, "video_flush", 256, NULL, (tskIDLE_PRIORITY + 2), &video_flush_handler);
    vTaskCoreAffinitySet(video_flush_handler, (1 << 1));

    TaskHandle_t read_adc_value_handler;
    xTaskCreate(read_adc_value, "read_adc_value", 600, NULL, (tskIDLE_PRIORITY + 1), &read_adc_value_handler);
    vTaskCoreAffinitySet(read_adc_value_handler, (1 << 0));

    backlight_driver_init();
    backlight_set_level(100);
    printf("backlight set to 100%%\n");

    printf("calling freertos scheduler, %lld\n", time_us_64());
    vTaskStartScheduler();
    for (;;)
        ;

    return 0;
}
